#include <bits/stdc++.h>
using namespace std;

/*
1418. 点菜展示表
已解答
中等
相关标签
相关企业
提示
给你一个数组 orders，表示客户在餐厅中完成的订单，确切地说， orders[i]=[customerNamei,tableNumberi,foodItemi] ，其中 customerNamei 是客户的姓名，tableNumberi 是客户所在餐桌的桌号，而 foodItemi 是客户点的餐品名称。

请你返回该餐厅的 点菜展示表 。在这张表中，表中第一行为标题，其第一列为餐桌桌号 “Table” ，后面每一列都是按字母顺序排列的餐品名称。接下来每一行中的项则表示每张餐桌订购的相应餐品数量，第一列应当填对应的桌号，后面依次填写下单的餐品数量。

注意：客户姓名不是点菜展示表的一部分。此外，表中的数据行应该按餐桌桌号升序排列。

 

示例 1：

输入：orders = [["David","3","Ceviche"],["Corina","10","Beef Burrito"],["David","3","Fried Chicken"],["Carla","5","Water"],["Carla","5","Ceviche"],["Rous","3","Ceviche"]]
输出：[["Table","Beef Burrito","Ceviche","Fried Chicken","Water"],["3","0","2","1","0"],["5","0","1","0","1"],["10","1","0","0","0"]] 
解释：
点菜展示表如下所示：
Table,Beef Burrito,Ceviche,Fried Chicken,Water
3    ,0           ,2      ,1            ,0
5    ,0           ,1      ,0            ,1
10   ,1           ,0      ,0            ,0
对于餐桌 3：David 点了 "Ceviche" 和 "Fried Chicken"，而 Rous 点了 "Ceviche"
而餐桌 5：Carla 点了 "Water" 和 "Ceviche"
餐桌 10：Corina 点了 "Beef Burrito" 
示例 2：

输入：orders = [["James","12","Fried Chicken"],["Ratesh","12","Fried Chicken"],["Amadeus","12","Fried Chicken"],["Adam","1","Canadian Waffles"],["Brianna","1","Canadian Waffles"]]
输出：[["Table","Canadian Waffles","Fried Chicken"],["1","2","0"],["12","0","3"]] 
解释：
对于餐桌 1：Adam 和 Brianna 都点了 "Canadian Waffles"
而餐桌 12：James, Ratesh 和 Amadeus 都点了 "Fried Chicken"
示例 3：

输入：orders = [["Laura","2","Bean Burrito"],["Jhon","2","Beef Burrito"],["Melissa","2","Soda"]]
输出：[["Table","Bean Burrito","Beef Burrito","Soda"],["2","1","1","1"]]
 

提示：

1 <= orders.length <= 5 * 10^4
orders[i].length == 3
1 <= customerNamei.length, foodItemi.length <= 20
customerNamei 和 foodItemi 由大小写英文字母及空格字符 ' ' 组成。
tableNumberi 是 1 到 500 范围内的整数。
*/

// 法一
class Solution {
public:
	vector<vector<string>> displayTable(vector<vector<string>>& orders) {
		set<string> foods;       // 字母排序所有餐品
		map<int, unordered_map<string, int>> tableMap;  // 桌号排序 菜品数量
		// 订单遍历
		for (const auto& order : orders) {
			int table = stoi(order[1]);
			const string& food = order[2];
			foods.insert(food);
			tableMap[table][food]++;
		}
		// 标题行
		vector<vector<string>> ans;
		vector<string> header = {"Table"};
		for (const auto& food : foods)  header.push_back(food);
		ans.push_back(header);
		// 数据行
		for (auto& entry : tableMap) {
			vector<string> row;
			row.push_back(to_string(entry.first)); // 桌号
			for (const auto& food : foods) {
				// 查找当前菜品在该桌的数量，不存在则为0
				int count = entry.second.count(food) ? entry.second.at(food) : 0;
				row.push_back(to_string(count));
			}
			ans.push_back(row);
		}
		return ans;
	}
};

// 法二
class Solution {
public:
	vector<vector<string>> displayTable(vector<vector<string>>& orders) {
		// 数据结构初始化 -------------------------------------------------
		set<string> mysetc;      // 自动排序的菜品集合（去重+字典序）[1,5](@ref)
		set<int> mysetz;         // 自动排序的桌号集合（升序排列）[1](@ref)

		// 收集所有菜品和桌号 ---------------------------------------------
		for (int i = 0; i < orders.size(); i++) 
		{
			mysetc.emplace(orders[i][2]);        // 提取菜品到集合
			mysetz.emplace(stoi(orders[i][1]));  // 提取桌号并转整型（stod应为stoi）
		}

		// 构建表头映射关系 -----------------------------------------------
		vector<string> t0 = {"Table"};           // 表头行（首列固定为Table）
		unordered_map<string, int> foodIndex;    // 菜品->列索引映射
		int n = 1;
		for (auto& x : mysetc) {
			t0.push_back(x);        // 按字典序填充菜品列
			foodIndex[x] = n++;     // 建立菜品索引映射
		}

		// 构建桌号映射关系 -----------------------------------------------
		vector<int> t1;                      // 排序后的桌号列表
		unordered_map<int, int> tableIndex;  // 桌号->行索引映射
		n = 1;
		for (auto& x : mysetz) {
			t1.push_back(x);       // 已排序的桌号列表
			tableIndex[x] = n++;   // 建立桌号索引映射
		}

		// 初始化结果矩阵（潜在问题：行数计算错误）-------------------------
		// 问题点：桌号数量为N时，需要N+1行（表头+数据），但t1.size()已包含排序后的桌号
		vector<vector<string>> res(tableIndex.size() + 1, vector<string>(foodIndex.size() + 1, "0")); 
		res[0] = t0;  // 直接设置表头更高效[8](@ref)

		// 填充订单数据（存在逻辑错误）------------------------------------
		for (int i = 0; i < orders.size(); i++)
		{
			// 错误点：此处试图初始化表头，但会导致后续订单覆盖表头数据
			/* （应删除此段错误逻辑）
			if (i == 0) {
				for (int j = 0; j < t0.size(); j++) {
					res[i][j] = t0[j];
				}
			}
			*/
			
			int table = stoi(orders[i][1]);       // 获取当前桌号
			const string& food = orders[i][2];   // 获取当前菜品
			
			int row = tableIndex[table];         // 获取结果矩阵行号
			res[row][0] = orders[i][1];          // 设置桌号列
			
			int col = foodIndex[food];           // 获取菜品所在列
			// 安全转换：字符串转整型再计算（stoi替代stod更合适）[3](@ref)
			int count = stoi(res[row][col]) + 1; 
			res[row][col] = to_string(count);    // 更新菜品数量
		}
		
		return res;
	}
};